/*
 * Copyright 2013 JROSE
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jrose.service.provider.user;

import lombok.NoArgsConstructor;
import org.apache.commons.lang3.Validate;
import org.jrose.api.annotation.remote.ExposeHttpService;
import org.jrose.core.util.RandomUtils;
import org.jrose.core.util.UserPassword;
import org.jrose.entity.config.Career;
import org.jrose.entity.config.InitialAttribute;
import org.jrose.entity.config.Lineup;
import org.jrose.entity.constant.RoleType;
import org.jrose.entity.constant.UserStatus;
import org.jrose.entity.constant.UserType;
import org.jrose.entity.data.Attribute;
import org.jrose.entity.data.Role;
import org.jrose.entity.data.Team;
import org.jrose.entity.data.TeamLineup;
import org.jrose.entity.data.User;
import org.jrose.service.provider.AbstractService;
import org.jrose.service.user.UserService;
import org.jrose.service.user.UserSignupContext;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Named;
import java.util.ArrayList;
import java.util.List;

import static org.jrose.core.util.RandomUtils.nextInt;

/**
 * Default {@link UserService} implementation.
 *
 * @author Xiaohai Zhang
 * @since 2013-09-01 16:40
 */
@Named
@NoArgsConstructor
@ExposeHttpService(name = "/userService", serviceInterface = UserService.class)
public class UserServiceImpl extends AbstractService implements UserService {
    @Override
    @Transactional
    public User signup(UserSignupContext context) {
        Validate.notNull(context, "UserSignupContext must not be null");
        context.validate();
        UserPassword userPassword = UserPassword.newInstance(context.getPassword());

        if (userLoader.loadByUsername(context.getUsername()) != null) {
            throw new IllegalArgumentException("Duplicated username '" + context.getUsername() + "'");
        }

        User user = User.newInstance(context.getUsername(), userPassword.getPassword(), userPassword.getSalt(), userPassword.getPlainPassword());
        user.setUserStatus(UserStatus.NEONATAL);
        user.setUserType(UserType.PLAYER);
        Long userId = userPersistence.persist(user).getId();
        log.debug("User persisted, the id is '{}'", userId);

        Team team = Team.newInstance(userId);
        team.setName("");
        team.setDescription("");
        Long teamId = teamPersistence.persist(team).getId();
        log.debug("Team persisted, the id is '{}'", teamId);

        List<Lineup> availableLineups = lineupLoader.loadInitialAvailableLineups();
        List<TeamLineup> teamLineups = new ArrayList<>();
        for (Lineup lineup : availableLineups) {
            TeamLineup teamLineup = TeamLineup.newInstance(teamId, lineup.getId());
            teamLineup.setActive(false);
            teamLineups.add(teamLineup);
        }
        RandomUtils.randomListElement(teamLineups).setActive(true);
        for (TeamLineup teamLineup : teamLineups) {
            teamLineupPersistence.persist(teamLineup);
        }
        log.debug("TeamLineup persisted, the count is '{}'", teamLineups.size());

        Role role = Role.newInstance(teamId, context.getRolename(), RoleType.LEADER, context.getRace(), context.getGender());
        Career initialCareer = careerLoader.loadInitialCareer();
        role.setCareerId(initialCareer.getId());
        role.setImgUrl("");
        Long roleId = rolePersistence.persist(role).getId();
        log.debug("Role persisted, the id is '{}'", roleId);

        InitialAttribute initialAttribute = initialAttributeLoader.load();
        Attribute attribute = newAttribute(roleId, initialAttribute);
        Long attributeId = attributePersistence.persist(attribute).getId();
        log.debug("Attribute persisted, the id is '{}'", attributeId);

        return user;
    }

    private Attribute newAttribute(Long roleId, InitialAttribute initialAttribute) {
        Attribute attribute = Attribute.newInstance(roleId);
        attribute.setMaxHealth(nextInt(initialAttribute.getLoMaxHealth(), initialAttribute.getHiMaxHealth()));
        attribute.setHealth(attribute.getMaxHealth());
        attribute.setMaxMana(nextInt(initialAttribute.getLoMaxMana(), initialAttribute.getHiMaxMana()));
        attribute.setMana(attribute.getMaxMana());
        attribute.setAttack(nextInt(initialAttribute.getLoAttack(), initialAttribute.getHiAttack()));
        attribute.setDefense(nextInt(initialAttribute.getLoDefense(), initialAttribute.getHiDefense()));
        attribute.setSpiritAttack(nextInt(initialAttribute.getLoSpiritAttack(), initialAttribute.getHiSpiritAttack()));
        attribute.setSpiritDefense(nextInt(initialAttribute.getLoSpiritDefense(), initialAttribute.getHiSpiritDefense()));
        attribute.setSpeed(nextInt(initialAttribute.getLoSpeed(), initialAttribute.getHiSpeed()));
        return attribute;
    }
}
